/*
* Author: Chris Seguin
*
* This software has been developed under the copyleft
* rules of the GNU General Public License. Please
* consult the GNU General Public License for more
* details about use and distribution of this software.
*/
package org.acm.seguin.refactor.method;
import java.util.Iterator;
import org.acm.seguin.parser.ast.ASTBlock;
import org.acm.seguin.parser.ast.ASTClassBodyDeclaration;
import org.acm.seguin.parser.ast.ASTClassDeclaration;
import org.acm.seguin.parser.ast.ASTFormalParameter;
import org.acm.seguin.parser.ast.ASTFormalParameters;
import org.acm.seguin.parser.ast.ASTInterfaceDeclaration;
import org.acm.seguin.parser.ast.ASTMethodDeclaration;
import org.acm.seguin.parser.ast.ASTMethodDeclarator;
import org.acm.seguin.parser.ast.ASTName;
import org.acm.seguin.parser.ast.ASTNameList;
import org.acm.seguin.parser.ast.ASTPrimitiveType;
import org.acm.seguin.parser.ast.ASTResultType;
import org.acm.seguin.parser.ast.ASTType;
import org.acm.seguin.parser.ast.ASTTypeDeclaration;
import org.acm.seguin.parser.ast.ASTVariableDeclaratorId;
import org.acm.seguin.parser.ast.SimpleNode;
import org.acm.seguin.pretty.ModifierHolder;
import org.acm.seguin.refactor.TransformAST;
import org.acm.seguin.summary.MethodSummary;
import org.acm.seguin.summary.ParameterSummary;
import org.acm.seguin.summary.TypeDeclSummary;
/**
* A series of transformations taht adds a new method to a class.
*
*@author Chris Seguin
*/
abstract class AddNewMethod extends TransformAST {
/**
* Description of the Field
*/
protected MethodSummary methodSummary;
/**
* Constructor for the AddNewMethod object
*
*@param init the method summary to add
*/
public AddNewMethod(MethodSummary init) {
methodSummary = init;
}
/**
* Update the syntax tree
*
*@param root the root of the syntax tree
*/
public void update(SimpleNode root) {
// Find the type declaration
int last = root.jjtGetNumChildren();
for (int ndx = 0; ndx < last; ndx++) {
if (root.jjtGetChild(ndx) instanceof ASTTypeDeclaration) {
drillIntoType((SimpleNode) root.jjtGetChild(ndx));
return;
}
}
}
/**
* Sets up the modifiers
*
*@param source the source holder
*@param dest the destination holder
*/
protected void setupModifiers(ModifierHolder source, ModifierHolder dest) {
dest.copy(source);
}
/**
* Determines if the method is abstract
*
*@return true if the method is abstract
*/
protected boolean isAbstract() {
return methodSummary.getModifiers().isAbstract();
}
/**
* Adds the return to the method declaration
*
*@param methodDecl The feature to be added to the Return attribute
*@param index The feature to be added to the Return attribute
*/
protected void addReturn(SimpleNode methodDecl, int index) {
ASTResultType result = new ASTResultType(0);
TypeDeclSummary returnType = methodSummary.getReturnType();
if ((returnType != null) && !returnType.getType().equals("void")) {
ASTType type = buildType(returnType);
result.jjtAddChild(type, 0);
}
methodDecl.jjtAddChild(result, index);
}
/**
* Creates the parameters
*
*@return Description of the Returned Value
*/
protected ASTFormalParameters createParameters() {
ASTFormalParameters params = new ASTFormalParameters(0);
Iterator iter = methodSummary.getParameters();
if (iter != null) {
int paramCount = 0;
while (iter.hasNext()) {
ParameterSummary paramSummary = (ParameterSummary) iter.next();
ASTFormalParameter nextParam = new ASTFormalParameter(0);
ASTType type = buildType(paramSummary.getTypeDecl());
nextParam.jjtAddChild(type, 0);
ASTVariableDeclaratorId paramDeclID = new ASTVariableDeclaratorId(0);
paramDeclID.setName(paramSummary.getName());
nextParam.jjtAddChild(paramDeclID, 1);
params.jjtAddChild(nextParam, paramCount);
paramCount++;
}
}
return params;
}
/**
* Creates the exceptions
*
*@param iter Description of Parameter
*@return Description of the Returned Value
*/
protected ASTNameList createExceptions(Iterator iter) {
ASTNameList list = new ASTNameList(0);
int ndx = 0;
while (iter.hasNext()) {
TypeDeclSummary next = (TypeDeclSummary) iter.next();
list.jjtAddChild(buildName(next), ndx);
ndx++;
}
return list;
}
/**
* Adds the exceptions to the node
*
*@param methodDecl The feature to be added to the Exceptions attribute
*@param index The feature to be added to the Exceptions attribute
*@return Description of the Returned Value
*/
protected int addExceptions(SimpleNode methodDecl, int index) {
Iterator iter = methodSummary.getExceptions();
if (iter != null) {
ASTNameList list = createExceptions(iter);
methodDecl.jjtAddChild(list, index);
index++;
}
return index;
}
/**
* Adds the body of the method
*
*@param methodDecl The feature to be added to the Body attribute
*@param index The feature to be added to the Body attribute
*/
protected void addBody(SimpleNode methodDecl, int index) {
if (!isAbstract()) {
ASTBlock block = new ASTBlock(0);
methodDecl.jjtAddChild(block, index);
}
}
/**
* Drills down into the class definition to add the method
*
*@param node the type syntax tree node that is being modified
*/
private void drillIntoType(SimpleNode node) {
if (node.jjtGetChild(0) instanceof ASTClassDeclaration) {
ASTClassDeclaration classDecl = (ASTClassDeclaration) node.jjtGetChild(0);
if (isAbstract()) {
classDecl.addModifier("abstract");
}
SimpleNode unmodified = (SimpleNode) classDecl.jjtGetChild(0);
SimpleNode classBody = (SimpleNode) unmodified.jjtGetChild(unmodified.jjtGetNumChildren() - 1);
ASTClassBodyDeclaration decl = new ASTClassBodyDeclaration(0);
decl.jjtAddChild(build(true), 0);
classBody.jjtAddChild(decl, classBody.jjtGetNumChildren());
}
else if (node.jjtGetChild(0) instanceof ASTInterfaceDeclaration) {
ASTInterfaceDeclaration classDecl = (ASTInterfaceDeclaration) node.jjtGetChild(0);
SimpleNode unmodified = (SimpleNode) classDecl.jjtGetChild(0);
SimpleNode classBody = (SimpleNode) unmodified.jjtGetChild(unmodified.jjtGetNumChildren() - 1);
classBody.jjtAddChild(build(false), classBody.jjtGetNumChildren());
}
}
/**
* Builds the method to be adding
*
*@param addBody Description of Parameter
*@return a syntax tree branch containing the new method
*/
private ASTMethodDeclaration build(boolean addBody) {
ASTMethodDeclaration methodDecl = new ASTMethodDeclaration(0);
// Set the modifiers
setupModifiers(methodSummary.getModifiers(),
methodDecl.getModifiers());
// Set return type
addReturn(methodDecl, 0);
// Set the declaration
ASTMethodDeclarator declarator = new ASTMethodDeclarator(0);
declarator.setName(methodSummary.getName());
ASTFormalParameters params = createParameters();
declarator.jjtAddChild(params, 0);
methodDecl.jjtAddChild(declarator, 1);
int index = 2;
index = addExceptions(methodDecl, index);
if (addBody) {
addBody(methodDecl, index);
}
return methodDecl;
}
/**
* Builds the type from the type declaration summary
*
*@param summary the summary
*@return the AST type node
*/
private ASTType buildType(TypeDeclSummary summary) {
ASTType type = new ASTType(0);
if (summary.isPrimitive()) {
ASTPrimitiveType addition = new ASTPrimitiveType(0);
addition.setName(summary.getLongName());
type.jjtAddChild(addition, 0);
}
else {
ASTName name = buildName(summary);
type.jjtAddChild(name, 0);
}
type.setArrayCount(summary.getArrayCount());
return type;
}
/**
* Builds the name of the type from the type decl summary
*
*@param summary the summary
*@return the name node
*/
private ASTName buildName(TypeDeclSummary summary) {
ASTName name = new ASTName(0);
name.fromString(summary.getLongName());
return name;
}
}